package com.zkh.myutils.json;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.zkh.myutils.bean.BeanBaseTypeConverter;
import com.zkh.myutils.bean.BeanUtils;
import com.zkh.myutils.bean.TypeConverter;
import com.zkh.myutils.utils.Assert;
import com.zkh.myutils.utils.DateUtils;
import com.zkh.myutils.utils.Regexp;
import com.zkh.myutils.utils.UtilsException;

/**
 * JSON父类，提供一些公共方法供JSONObject和JSONArray使用
 * @author zkh
 */
public class JSON {

	// 转换器
	protected TypeConverter converter;

	/**
	 * 获取JSON对象。根据参数类型，可强转为JSONObject（为null和对象时）和JSONArray（为Collection和数组时）类型。<br />
	 * @param obj 待转换为JSON对象的参数，当参数为String类型时，会当作JSON字符串解析。不符合JSON格式，将抛出异常。
	 * @return
	 */
	public static JSON getJSON(Object obj) {
		return getJSON(obj, null);
	}

	/**
	 * 获取JSON对象。根据参数类型，可强转为JSONObject（为null和对象时）和JSONArray（为Collection和数组时）类型。<br />
	 * @param obj 待转换为JSON对象的参数，当参数为String类型时，会当作JSON字符串解析。不符合JSON格式，将抛出异常。
	 * @return
	 */
	public static JSON getJSON(Object obj, TypeConverter converter) {
		//Object类型
		boolean isObj = true;
		//不为空
		if(obj != null) {
			//数组
			if(obj.getClass().isArray() || obj instanceof List<?>) {
				isObj = false;
			}
			//字符串数组
			else if(obj instanceof String && Regexp.isMatch("\\s*\\[.*\\]\\s*", obj.toString())) {
				isObj = false;
			}
		}
		//按类型实例化对应JSON对象
		return isObj ? new JSONObject(obj, converter) : new JSONArray(obj, converter);
	}
	
	/**
	 * 是否为空，具体实现由子类提供，此处false无意义。
	 * @return
	 */
	public boolean isEmpty() {
		return false;
	}
	
	/**
	 * 转换为JSON字符串，具体实现由子类提供，此处空字符串无意义。
	 * @return
	 */
	public String toString() {
		return "";
	}
	
	/**
	 * 转换为JSON字符串，具体实现由子类提供，此处空字符串无意义。
	 * @param ignoreNullValueKey 是否忽略值为null的key
	 * @return
	 */
	public String toString(boolean ignoreNullValueKey) {
		return "";
	}

	/**
	 * 获取默认格式的Date值，可解析yyyy-MM-dd和yyyy-MM-dd HH:mm:ss
	 * @param date
	 * @return
	 */
	protected Date getDefaultDate(String date) {
		// 格式转换
		if (date == null) {
			return null;
		}
		// 格式对象
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		// 转换
		try {
			return sdf.parse(date);
		} catch (ParseException e) {
			// 重置格式
			sdf.applyPattern("yyyy-MM-dd");
			// 转换
			try {
				return sdf.parse(date);
			} catch (ParseException e1) {
				throw new UtilsException("日期转换失败", e1);
			}
		}
	}

	/**
	 * 格式化日期
	 * @param date
	 * @param format
	 * @return
	 */
	protected Date getDate(String date, String format) {
		return Assert.getIfNotNull(date, e->DateUtils.getDate(e, format));
	}

	/**
	 * List转String
	 * @param jsonObjectList 集合
	 * @param ignoreNullValueKey 是否忽略值为null的key
	 * @return
	 */
	protected String toString(List<Object> jsonObjectList, boolean ignoreNullValueKey) {
		// 字符
		StringBuilder sb = new StringBuilder("[");
		// map集合长度
		int len = jsonObjectList.size();
		// 计数
		int count = 0;
		// 遍历
		for (Object val : jsonObjectList) {
			// 当前数量
			count++;
			// 解析值
			parseValue(val, sb, count < len, ignoreNullValueKey);
		}
		// 闭合
		sb.append("]");
		// 返回
		return sb.toString();
	}

	/**
	 * Map转String
	 * @param jsonObjectMap 对象
	 * @param ignoreNullValueKey 是否忽略值为null的key
	 * @return
	 */
	protected String toString(Map<String, Object> jsonObjectMap, boolean ignoreNullValueKey) {
		// 字符
		StringBuilder sb = new StringBuilder("{");
		// map集合长度
		int len = jsonObjectMap.keySet().size();
		// 计数
		int count = 0;
		// 遍历取值
		for (Entry<String, Object> kv : jsonObjectMap.entrySet()) {
			// 当前数量
			count++;
			//值为空
			if(kv.getValue()==null && ignoreNullValueKey) {
				//如果没有后续，则删除末尾逗号
				if(count >= len) {
					sb.deleteCharAt(sb.length()-1);
				}
			}else {
				// 保存key
				sb.append("\"" + kv.getKey() + "\":");
				// 解析值
				parseValue(kv.getValue(), sb, count < len, ignoreNullValueKey);
			}
		}
		//检查是否为空
		if(sb.length()==0) {
			sb.insert(0, "{");
		}
		// 闭合
		sb.append("}");
		// 返回字符串
		return sb.toString();
	}

	/**
	 * 解析值
	 * @param val 待解析的值
	 * @param sb 解析后的容器
	 * @param appendComma 是否追加逗号
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private void parseValue(Object val, StringBuilder sb, boolean appendComma, boolean ignoreNullValueKey) {
		// 值类型
		String type = val == null ? null : val.getClass().getSimpleName();
		// 空
		if (val == null) {
			sb.append("null");
		}
		// 基础类型
		else if (BeanBaseTypeConverter.notParseType.contains(type)) {
			if ("char".equals(type) || "Character".equals(type)) {
				sb.append("\"" + val + "\"");
			} else {
				sb.append(val.toString());
			}
		}
		// 字符串
		else if (val instanceof String) {
			sb.append("\"" + val.toString().replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r") + "\"");
		}
		// 嵌套对象
		else if (val instanceof Map) {
			sb.append(toString((Map<String, Object>) val, ignoreNullValueKey));
		}
		// 嵌套集合
		else if (val instanceof List) {
			sb.append(toString((List<Object>) val, ignoreNullValueKey));
		}
		//其它无法解析的类型
		else {
			sb.append("\""+val.toString().replace("\\", "\\\\").replace("\"", "\\\"")+"\"");
		}
		// 还有数据，追加逗号
		if (appendComma) {
			sb.append(",");
		}
	}

	/**
	 * JSON对象转指定对象
	 * @param type 指定对象类型
	 * @return
	 */
	protected <T> T parseEntity(Map<String, Object> jsonObjectMap, Class<T> cls) {
		return BeanUtils.mapToBean(jsonObjectMap, cls, this.converter);
	}

	/**
	 * JSON对象转集合
	 * @param type 集合元素类型
	 * @return
	 */
	protected <T> List<T> parseList(List<Object> jsonObjectList, Class<T> type) {
		//返回集合
		return BeanUtils.listToBean(jsonObjectList, type, this.converter);
	}
}
